// ==================== 2. API调用服务 ====================
package org.chen.flight.service.flight;

import lombok.extern.slf4j.Slf4j;
import org.chen.common.flight.dto.FlightApiConfigDTO;
import org.chen.common.flight.*;
import org.chen.common.flight.request.FlightSearchRequest;
import org.chen.common.flight.response.OneWayFlightSearchResponse;
import org.chen.common.flight.response.RoundTripFlightSearchResponse;
import org.chen.common.result.ResultVO;
import org.chen.flight.feign.SystemClient;
import org.chen.flight.util.SignUtils;
import org.chen.flight.util.UrlBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * 机票API调用服务
 * 负责与携程API的交互
 */
@Service
@Slf4j
public class FlightApiService {

    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired
    private FlightDataParseService dataParseService;

    @Autowired
    private SystemClient systemConfigService;

    @Autowired
    private OneWayFlightParseService oneWayParseService;

    @Autowired
    private RoundTripFlightParseService roundTripFlightParseService;

    // 新增常量
    private static final String BATCH_SEARCH_URL = "https://flights.ctrip.com/international/search/api/search/batchSearch";
    private static final String PULL_SEARCH_URL = "https://flights.ctrip.com/international/search/api/search/pull/";
    private static final int PULL_RETRY_COUNT = 3;
    private static final int TRANSACTION_RETRY_COUNT = 2; // 重新获取transactionID的重试次数
    private static final String[] USER_AGENTS = {
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    };

    /**
     * 第一步：获取transactionID和基础数据
     */
    public FlightSearchData getTransactionData(FlightSearchRequest request) {
        String url = UrlBuilder.buildCtripSearchUrl(request);
        log.info("url: {}", url);

        HttpHeaders headers = new HttpHeaders();
        headers.set("accept", "application/json");
        headers.set("User-Agent", USER_AGENTS[new Random().nextInt(USER_AGENTS.length)]);

        HttpEntity<String> entity = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
            Map<String, Object> responseBody = response.getBody();

            if (responseBody == null || !"success".equals(responseBody.get("msg"))) {
                throw new RuntimeException("API调用失败: " + responseBody);
            }

            Map<String, Object> data = (Map<String, Object>) responseBody.get("data");
            if (data == null || !data.containsKey("transactionID")) {
                throw new RuntimeException("未能获取到transactionID");
            }

            return dataParseService.parseSearchData(data, request);

        } catch (Exception e) {
            log.error("获取transactionID失败: {}", e.getMessage());
            throw new RuntimeException("获取transactionID失败: " + e.getMessage());
        }
    }

    /**
     * 使用pull API获取航班数据
     */
    private Map<String, Object> pullFlightData(String searchId, FlightSearchData searchData) {
        String pullUrl = PULL_SEARCH_URL + searchId;
        HttpHeaders headers = buildBatchSearchHeaders(searchData);
        Map<String, Object> requestBody = buildBatchSearchRequest(searchData);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

        try {
            log.info("使用pull API获取数据: {}", pullUrl);
            ResponseEntity<Map> response = restTemplate.exchange(pullUrl, HttpMethod.POST, entity, Map.class);
            return response.getBody();
        } catch (Exception e) {
            log.error("Pull API调用失败: {}", e.getMessage());
            throw new RuntimeException("Pull API调用失败: " + e.getMessage());
        }
    }

    /**
     * 检查响应中是否包含searchId
     */
    private String extractSearchId(Map<String, Object> responseBody) {
        if (responseBody == null) {
            return null;
        }

        Map<String, Object> data = (Map<String, Object>) responseBody.get("data");
        if (data == null) {
            return null;
        }

        Map<String, Object> context = (Map<String, Object>) data.get("context");
        if (context == null) {
            return null;
        }

        return (String) context.get("searchId");
    }

    /**
     * 检查响应中是否包含有效的航班数据
     */
    private boolean hasValidFlightData(Map<String, Object> responseBody) {
        if (responseBody == null) {
            return false;
        }

        Map<String, Object> data = (Map<String, Object>) responseBody.get("data");
        if (data == null) {
            return false;
        }

        List<Object> flightItineraryList = (List<Object>) data.get("flightItineraryList");
        return flightItineraryList != null && !flightItineraryList.isEmpty();
    }

    private Map<String, Object> buildBatchSearchRequest(FlightSearchData searchData) {
        Map<String, Object> request = new HashMap<>();
        request.put("adultCount", searchData.getAdultCount());
        request.put("childCount", searchData.getChildCount());
        request.put("infantCount", searchData.getInfantCount());
        request.put("flightWay", searchData.getFlightWay());
        request.put("cabin", searchData.getCabin());
        request.put("scope", searchData.getScope());
        request.put("extensionAttributes", searchData.getExtensionAttributes());
        request.put("segmentNo", searchData.getSegmentNo());
        request.put("transactionID", searchData.getTransactionID());
        request.put("directFlight", searchData.isDirectFlight());
        request.put("extGlobalSwitches", searchData.getExtGlobalSwitches());
        request.put("noRecommend", searchData.isNoRecommend());

        List<Map<String, Object>> segments = new ArrayList<>();
        for (FlightSegment segment : searchData.getFlightSegments()) {
            segments.add(convertFlightSegmentToMap(segment));
        }
        request.put("flightSegments", segments);

        return request;
    }

    private HttpHeaders buildBatchSearchHeaders(FlightSearchData searchData) {
        ResultVO<FlightApiConfigDTO> vo = systemConfigService.getFlightApiConfig();
        FlightApiConfigDTO apiConfig = vo.getData();
        String cookie = apiConfig.getCookie();
        String token = apiConfig.getToken();
        HttpHeaders headers = new HttpHeaders();
        headers.set("accept", "application/json");
        headers.set("Content-Type", "application/json");
        headers.set("User-Agent", USER_AGENTS[new Random().nextInt(USER_AGENTS.length)]);
        headers.set("transactionid", searchData.getTransactionID());
        headers.set("Cookie", cookie);
        headers.set("token", token);

        String sign = SignUtils.generateCtripSign(searchData);
        headers.set("sign", sign);

        log.info("构造请求头 - transactionID: {}, sign: {}", searchData.getTransactionID(), sign);
        return headers;
    }

    private Map<String, Object> convertFlightSegmentToMap(FlightSegment segment) {
        Map<String, Object> map = new HashMap<>();
        map.put("departureCityCode", segment.getDepartureCityCode());
        map.put("arrivalCityCode", segment.getArrivalCityCode());
        map.put("departureCityName", segment.getDepartureCityName());
        map.put("arrivalCityName", segment.getArrivalCityName());
        map.put("departureDate", segment.getDepartureDate());
        map.put("departureCountryId", segment.getDepartureCountryId());
        map.put("departureCountryName", segment.getDepartureCountryName());
        map.put("departureCountryCode", segment.getDepartureCountryCode());
        map.put("departureProvinceId", segment.getDepartureProvinceId());
        map.put("departureCityId", segment.getDepartureCityId());
        map.put("arrivalCountryId", segment.getArrivalCountryId());
        map.put("arrivalCountryName", segment.getArrivalCountryName());
        map.put("arrivalCountryCode", segment.getArrivalCountryCode());
        map.put("arrivalProvinceId", segment.getArrivalProvinceId());
        map.put("arrivalCityId", segment.getArrivalCityId());
        map.put("departureCityTimeZone", segment.getDepartureCityTimeZone());
        map.put("arrivalCityTimeZone", segment.getArrivalCityTimeZone());
        map.put("timeZone", segment.getTimeZone());
        return map;
    }

    public OneWayFlightSearchResponse getFlightDetailsOneWayRaw(FlightSearchData searchData, FlightSearchRequest request) {
        ResultVO<FlightApiConfigDTO> vo = systemConfigService.getFlightApiConfig();
        FlightApiConfigDTO apiConfig = vo.getData();
        int maxRetries = apiConfig.getRetryCount();

        // 外层循环：重新获取transactionID的重试
        for (int transactionRetry = 0; transactionRetry <= TRANSACTION_RETRY_COUNT; transactionRetry++) {
            if (transactionRetry > 0) {
                log.info("重新获取transactionID，第 {} 次尝试", transactionRetry);
                try {
                    searchData = getTransactionData(request);
                } catch (Exception e) {
                    log.error("重新获取transactionID失败: {}", e.getMessage());
                    if (transactionRetry >= TRANSACTION_RETRY_COUNT) {
                        throw new RuntimeException("重新获取transactionID失败: " + e.getMessage());
                    }
                    continue;
                }
            }

            OneWayFlightSearchResponse oneWayFlightSearchResponse = null;

            // 内层循环：批量搜索的重试
            for (int currentAttempt = 0; currentAttempt <= maxRetries; currentAttempt++) {
                try {
                    log.info("尝试获取 单程 航班详细数据，第 {} 次尝试（transactionID: {})",
                            currentAttempt + 1, searchData.getTransactionID());

                    Map<String, Object> requestBody = buildBatchSearchRequest(searchData);
                    HttpHeaders headers = buildBatchSearchHeaders(searchData);
                    HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

                    ResponseEntity<Map> response = restTemplate.exchange(BATCH_SEARCH_URL, HttpMethod.POST, entity, Map.class);
                    Map<String, Object> responseBody = response.getBody();

                    // 检查是否有有效的航班数据
                    if (hasValidFlightData(responseBody)) {
                        OneWayFlightSearchResponse currentResponse = oneWayParseService.parseOneWayResponse(responseBody, searchData, request);
                        if (currentResponse != null &&
                                currentResponse.getFlights() != null && !currentResponse.getFlights().isEmpty()) {
                            log.info("成功获取到 {} 个 单程 航班数据，第 {} 次尝试成功",
                                    currentResponse.getFlights().size(), currentAttempt + 1);
                            return currentResponse;
                        }
                    }

                    // 检查是否包含searchId
                    String searchId = extractSearchId(responseBody);
                    if (searchId != null && !searchId.isEmpty()) {
                        log.info("获取到searchId: {}，开始使用pull API", searchId);

                        // 使用pull API重试
                        for (int pullRetry = 0; pullRetry < PULL_RETRY_COUNT; pullRetry++) {
                            try {
                                log.info("Pull API第 {} 次尝试 (searchId: {})", pullRetry + 1, searchId);
                                Thread.sleep(2000 + pullRetry * 1000L); // 等待时间递增

                                Map<String, Object> pullResponseBody = pullFlightData(searchId, searchData);

                                if (hasValidFlightData(pullResponseBody)) {
                                    OneWayFlightSearchResponse pullResponse = oneWayParseService.parseOneWayResponse(pullResponseBody, searchData, request);
                                    if (pullResponse != null &&
                                            pullResponse.getFlights() != null && !pullResponse.getFlights().isEmpty()) {
                                        log.info("Pull API成功获取到 {} 个 单程 航班数据，第 {} 次尝试成功",
                                                pullResponse.getFlights().size(), pullRetry + 1);
                                        return pullResponse;
                                    }
                                }
                                log.warn("Pull API第 {} 次尝试未获取到有效数据", pullRetry + 1);
                            } catch (Exception e) {
                                log.error("Pull API第 {} 次尝试失败: {}", pullRetry + 1, e.getMessage());
                            }
                        }

                        log.warn("Pull API重试 {} 次后仍未获取到数据，跳出当前批量搜索循环", PULL_RETRY_COUNT);
                        break; // 跳出批量搜索循环，进入下一轮transactionID重试
                    }

                    // 保存当前响应用于最终返回
                    if (responseBody != null) {
                        oneWayFlightSearchResponse = oneWayParseService.parseOneWayResponse(responseBody, searchData, request);
                    }

                    if (currentAttempt < maxRetries) {
                        log.warn("第 {} 次尝试未获取到 单程 航班数据，准备重试...", currentAttempt + 1);
                        Thread.sleep(1000 + currentAttempt * 1000L);
                    }

                } catch (Exception e) {
                    log.error("第 {} 次尝试获取 单程 机票详细数据失败: {}", currentAttempt + 1, e.getMessage());
                    if (currentAttempt >= maxRetries) {
                        if (transactionRetry < TRANSACTION_RETRY_COUNT) {
                            log.warn("批量搜索重试 {} 次失败，尝试重新获取transactionID", maxRetries);
                            break; // 跳出当前批量搜索循环，进入下一轮transactionID重试
                        } else {
                            throw new RuntimeException("获取 单程 机票详细数据失败（已重试" + maxRetries + "次）: " + e.getMessage());
                        }
                    }
                    try {
                        Thread.sleep(1000 + currentAttempt * 1000L);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            }

            // 如果是最后一次transactionID重试，返回结果
            if (transactionRetry >= TRANSACTION_RETRY_COUNT) {
                return oneWayFlightSearchResponse != null ? oneWayFlightSearchResponse : OneWayFlightSearchResponse.error("获取 单程 航班数据失败");
            }
        }

        return OneWayFlightSearchResponse.error("获取 单程 航班数据失败");
    }

    public RoundTripFlightSearchResponse getFlightDetailsRoundTripRaw(FlightSearchData searchData, FlightSearchRequest request) {
        ResultVO<FlightApiConfigDTO> vo = systemConfigService.getFlightApiConfig();
        FlightApiConfigDTO apiConfig = vo.getData();
        int maxRetries = apiConfig.getRetryCount();

        // 外层循环：重新获取transactionID的重试
        for (int transactionRetry = 0; transactionRetry <= TRANSACTION_RETRY_COUNT; transactionRetry++) {
            if (transactionRetry > 0) {
                log.info("重新获取transactionID，第 {} 次尝试", transactionRetry);
                try {
                    searchData = getTransactionData(request);
                } catch (Exception e) {
                    log.error("重新获取transactionID失败: {}", e.getMessage());
                    if (transactionRetry >= TRANSACTION_RETRY_COUNT) {
                        throw new RuntimeException("重新获取transactionID失败: " + e.getMessage());
                    }
                    continue;
                }
            }

            RoundTripFlightSearchResponse roundTripFlightSearchResponse = null;

            // 内层循环：批量搜索的重试
            for (int currentAttempt = 0; currentAttempt <= maxRetries; currentAttempt++) {
                try {
                    log.info("尝试获取 往返 航班详细数据，第 {} 次尝试（transactionID: {})",
                            currentAttempt + 1, searchData.getTransactionID());

                    Map<String, Object> requestBody = buildBatchSearchRequest(searchData);
                    HttpHeaders headers = buildBatchSearchHeaders(searchData);
                    HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

                    ResponseEntity<Map> response = restTemplate.exchange(BATCH_SEARCH_URL, HttpMethod.POST, entity, Map.class);
                    Map<String, Object> responseBody = response.getBody();

                    // 检查是否有有效的航班数据
                    if (hasValidFlightData(responseBody)) {
                        RoundTripFlightSearchResponse currentResponse = roundTripFlightParseService.parseRoundTripResponse(responseBody, searchData, request);
                        if (currentResponse != null && currentResponse.isSuccess() &&
                                currentResponse.getFlights() != null && !currentResponse.getFlights().isEmpty()) {
                            log.info("成功获取到 {} 个 往返 航班数据，第 {} 次尝试成功",
                                    currentResponse.getFlights().size(), currentAttempt + 1);
                            return currentResponse;
                        }
                    }

                    // 检查是否包含searchId
                    String searchId = extractSearchId(responseBody);
                    if (searchId != null && !searchId.isEmpty()) {
                        log.info("获取到searchId: {}，开始使用pull API", searchId);

                        // 使用pull API重试
                        for (int pullRetry = 0; pullRetry < PULL_RETRY_COUNT; pullRetry++) {
                            try {
                                log.info("Pull API第 {} 次尝试 (searchId: {})", pullRetry + 1, searchId);
                                Thread.sleep(2000 + pullRetry * 1000L); // 等待时间递增

                                Map<String, Object> pullResponseBody = pullFlightData(searchId, searchData);

                                if (hasValidFlightData(pullResponseBody)) {
                                    RoundTripFlightSearchResponse pullResponse = roundTripFlightParseService.parseRoundTripResponse(pullResponseBody, searchData, request);
                                    if (pullResponse != null && pullResponse.isSuccess() &&
                                            pullResponse.getFlights() != null && !pullResponse.getFlights().isEmpty()) {
                                        log.info("Pull API成功获取到 {} 个 往返 航班数据，第 {} 次尝试成功",
                                                pullResponse.getFlights().size(), pullRetry + 1);
                                        return pullResponse;
                                    }
                                }
                                log.warn("Pull API第 {} 次尝试未获取到有效数据", pullRetry + 1);
                            } catch (Exception e) {
                                log.error("Pull API第 {} 次尝试失败: {}", pullRetry + 1, e.getMessage());
                            }
                        }

                        log.warn("Pull API重试 {} 次后仍未获取到数据，跳出当前批量搜索循环", PULL_RETRY_COUNT);
                        break; // 跳出批量搜索循环，进入下一轮transactionID重试
                    }

                    // 保存当前响应用于最终返回
                    if (responseBody != null) {
                        roundTripFlightSearchResponse = roundTripFlightParseService.parseRoundTripResponse(responseBody, searchData, request);
                    }

                    if (currentAttempt < maxRetries) {
                        log.warn("第 {} 次尝试未获取到 往返 航班数据，准备重试...", currentAttempt + 1);
                        Thread.sleep(1000 + currentAttempt * 1000L);
                    }

                } catch (Exception e) {
                    log.error("第 {} 次尝试获取 往返 机票详细数据失败: {}", currentAttempt + 1, e.getMessage());
                    if (currentAttempt >= maxRetries) {
                        if (transactionRetry < TRANSACTION_RETRY_COUNT) {
                            log.warn("批量搜索重试 {} 次失败，尝试重新获取transactionID", maxRetries);
                            break; // 跳出当前批量搜索循环，进入下一轮transactionID重试
                        } else {
                            throw new RuntimeException("获取 往返 机票详细数据失败（已重试" + maxRetries + "次）: " + e.getMessage());
                        }
                    }
                    try {
                        Thread.sleep(1000 + currentAttempt * 1000L);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            }

            // 如果是最后一次transactionID重试，返回结果
            if (transactionRetry >= TRANSACTION_RETRY_COUNT) {
                return roundTripFlightSearchResponse != null ? roundTripFlightSearchResponse : RoundTripFlightSearchResponse.error("获取 往返 航班数据失败");
            }
        }

        return RoundTripFlightSearchResponse.error("获取 往返 航班数据失败");
    }
}